/**
 * @author Alvaro Videla <videlalvaro@gmail.com>
 * 
 * See LICENSE for terms of usage
 * 
 * CREDITS:
 * 
 * - Some ideas for view swapping taked from the ColdFire extension. http://coldfire.riaforge.org/
 * - Thanks to Christoph Dorn, Jan Odvarko for their tutorials on Firebug extensions.
 */

FBL.ns(function() { with (FBL) {

function firesymfonyPanel() {}

firesymfonyPanel.prototype = domplate(Firebug.Panel,
{
	/**
	 * Interface template representations.
	 */
	
	mainTag: DIV({'id': 'sfWebDebug'}, ""),
	
  	mainTabTag: DIV({'id': "$id", 'class': 'sfWebDebugTop'}, ""),
	
	aboutTag: 
	DIV({id: "fs-splash"},
		DIV({'class': "fs-splash-logo"}),
		DIV({'class': "fs-splash-title" },
			P("-    seamless symfony debugging")
		),
		DIV({"class": "fs-splash-background"}),
		DIV({"class": "fs-splash-help"},
			P("Click on Vars and Config, Logs and Messages, Database, Memory or Timer "),
			P("to access the symfony debug information")
		),
		DIV({"class": "fs-splash-author"},
			P("by Alvaro Videla - 2008")
		),
		DIV({"class": "fs-splash-website"},
			P(
				A({'href': "http://www.firesymfony.org/", 'target': "_blank"}, 
				  "[official firesymfony website]"
				)
			)
		)
	),

  	configurationDetailsTag: 
  	UL( {'id': "sfWebDebugConfigSummary"},
      	FOR("detail", "$config.content.details|asKeyValue",
        		LI({'class': "is$detail.value"}, "$detail.name")
      	)
  	),

  	configurationAndRequestTag:
  	DIV(
      	FOR("conf_data", "$config.content|asKeyValueRemoveDetails",
        		H2(
          		"$conf_data.name", 
          		A({'href': "#", 'onclick': "$sfWebDebugToggleMenu"},
            			IMG({src: "chrome://firesymfony/skin/toggle.gif", "alt": "Toggle"})
          		)
        		), //H2
        		DIV({'style':'display: none;', 'id': "$conf_data.name"},
          		PRE("$conf_data.value|convertQuotes")
        		) //DIV
      	) //FOR
  	),

  	logsHeadTag: 
  	UL({'id': 'sfWebDebugLogMenu'},
  		LI({onclick: "$toggleAllLogs"}, "[all]"),
  		LI({onclick: "$toggleAllLogs"}, "[none]"),
  		LI( {id: "sfWebDebugInfo", onclick: "$togglePriority"},
  			IMG({src: "chrome://firesymfony/skin/info.png"})
  		),
  		LI( {id: "sfWebDebugWarning", onclick: "$togglePriority"},
  			IMG({src: "chrome://firesymfony/skin/warning.png"})
  		),
  		LI( {id: "sfWebDebugError", onclick: "$togglePriority"},
  			IMG({src: "chrome://firesymfony/skin/error.png"})
  		),
  		FOR("type", "$logs.content.types|configIterator",
  			LI({onclick: "$onTypeClick"}, "$type")
  		)
      ),

  	logsTag: 
  	DIV({'id': 'sfWebDebugLogLines'},
  		TABLE({'class': 'sfWebDebugLogs'},
  			TBODY(
  				TR(
  		            TH('#'),
  		            TH('type'),
  		            TH('message')
              	), //TR
  	        	FOR("log_line", "$logs.content.logData|configIterator",
  	          		TR( {'class': 'sfWebDebugLogLine $log_line.type sfWebDebug$log_line.priority|firstCharToUpper'},
  	              		TD({'class': 'sfWebDebugLogNumber'}, "$log_line.line_nb"),
  	              		TD({'class': 'sfWebDebugLogType'}, 
  							IMG({src: "chrome://firesymfony/skin/$log_line.priority|appendPngExtension"}),
  	                  		"$log_line.type|formatLogType"
  	                	),
  	              		TD("$log_line.message|transformGt|transformLt")
  	           		) //TR
  	         	) //FOR
          	) //TBODY
		) //TABLE
    ),
	
	cacheHeadTag:
  	UL({'id': 'sfWebDebugLogMenu'},
  		LI(
			"Cache information - ",
			A({id: "$cache.content.reload_url", "href": "#", 'alt': "$cache|reloadCacheLinkText", onclick: "$reloadNoCache"},
				"$cache|reloadCacheLinkText ",
				IMG({src: "chrome://firesymfony/skin/reload.png"})
			)
		)
	),
	
	cacheTag:
	DIV({'id': 'sfWebDebugCacheLines'},
		TABLE({'class': 'sfWebDebugLogs'},
			TBODY(
				TR(
					TH("Last Modified"),
					TH("Lifetime"),
					TH("URI")
				),
				FOR("cache_line", "$cache.content.cache_info|configIterator",
					TR({'class': 'sfWebDebugLogLine', 'style': "background-color: $cache_line.is_new|getCacheLineColor"},
						TD({'class': 'sfWebDebugLogNumber'}, "$cache_line.last_modified"),
						TD({'class': 'sfWebDebugLogNumber'}, "$cache_line.life_time"),
						TD({'class': 'sfWebDebugLogType'}, 
							A({'id': "$cache_line.id",  onmouseover: "$highlightCachedElement", 'href': "#"},
								"$cache_line.uri|trasnformAmp"
							)
						)
					)
				)
			)
		)
	),
	
	databaseHeadTag: 
	DIV(
		SPAN("$database.title - Click on a query to copy it to clipboard.")
	),	

  	databaseTag:
	UL({'id': 'sfWebDebugDatabaseDetails'},
		FOR("queryLog", "$database.content|configIterator",
			LI(
				"$queryLog.time ",
				A({'href': "#", onclick: "$copyQueryToClipboard"},
					"$queryLog.query"
				) //A
			) //TR
		) // FOR
	),

  	memoryTag:
      DIV(
          SPAN("$memory.title $memory.content")
      ),

  	timersHeadTag: H1("Timers: $timer.content.total"),

  	timersDetailsTag: 
  	TABLE({'class': 'sfWebDebugLogs', 'style':'width: 300px;'},
      	TBODY(
  			TR(
  	        	TH('type'),
  	        	TH('calls'),
  	        	TH('time (ms)'),
  	        	TH('time (%)')
  			), //TR
  			FOR("timer_data", "$timer.content|timersIterator",
  	        	TR(
  					TD({'class': 'sfWebDebugLogType'},
  	            		"$timer_data.name"
  	          		), //TD
  	          		TD({'class': 'sfWebDebugLogNumber', 'style': 'text-align: right;'},
  	            		"$timer_data.calls"
  	          		), //TD
  	          		TD({'style': 'text-align: right;'},
  	            		"$timer_data.time"
  					), //TD
  	          		TD({'style': 'text-align: right;'},
  	            		"$timer_data.percent"
  	          		) //TD
  				) //TR
  			) //FOR
  		) //TBODY
  	),
  	
	/**
	 * Cache Helper Functions.
	 */
	
	reloadNoCache: function(event){
		var actual_location = FirebugContext.window.location.href;
		var new_location = "";
		if(actual_location.indexOf("?_sf_ignore_cache=1") > -1){
			var new_location =  actual_location.replace("?_sf_ignore_cache=1", "");
		} else{
			var new_location =  actual_location + event.target.parentNode.id;
		}
		FirebugContext.window.location = new_location;
		return false;
	},
	
	highlightCachedElement: function(event){
		try
		{
			var id = event.target.id;
			var element = FirebugContext.window.document.getElementById(id)
			if(element) {
				Firebug.Inspector.highlightObject(element, FirebugContext);
			}	
		}catch(e){;}
		return false;
	},
	
	/**
	 * Returns the text for the cache toggling link.
	 * @param {String} value
	 */
	reloadCacheLinkText: function(value){
		var actual_location = FirebugContext.window.location.href;
		if(actual_location.indexOf("?_sf_ignore_cache=1") > -1){
			return "reload page with cache";
		} else{
			return "reload page ignoring cache";
		}
	},
	
	/**
	 * Returns the css color value for a cache info line
	 * @param {Boolean} value the parameter to transform
	 */
	getCacheLineColor: function(value){
		return value ? '#9ff' : '#ff9';
	},
	
	/**
	 * Copies the clicked query to the clipboard
	 * @param {Object} event
	 */
	copyQueryToClipboard: function(event){
		var string = event.target.innerHTML;
		Firebug.Console.log(event.target);
		copyToClipboard(string);
		return false;
	},

	//TODO use Firebug helper function.
	asKeyValue: function(data){
    	var arr = new Array();
    	for(var prop in data ){
	      	var o = {};
	      	o.name = prop;
			o.value = data[prop];
			arr.push(o);
		}
		return arr;
	},

	//TODO use Firebug helper function.  
	asKeyValueRemoveDetails: function(data){
		var arr = new Array();
		for (var prop in data) {
			if (prop != 'details') {
				var o = {};
				o.name = prop;
				o.value = data[prop];
				arr.push(o);
			}
		}
		return arr;
	},
	
	/**
	 * Html Special Characters Converters
	 */

	convertQuotes: function(value){
		return value.replace(/&#039;/g, "'");
	},
	
    transformGt: function(value){
		return value.replace(/&gt;/g, ">");
    },

    transformLt: function(value){
		return value.replace(/&lt;/g, "<");
    },
	
	trasnformAmp: function(value){
		return value.replace(/&amp;/g, "&");
	},

	/**
	 * Return an Object as array. 
	 * The object property names became the array keys. 
	 * The properties became the array elements.
	 * 
	 * @param {Object} data
	 * @return {Array}
	 */
    configIterator: function(data)
    {
      var ret = new Array();
      for(var prop in data){
        //Skips protype.js object extensions
		if(typeof data[prop] != 'function'){
          ret.push(data[prop]);
        }
      }
      return ret;
    },
	
	/**
	 * Iterates over the timers array and removes the <total> entry.
	 * @param {Object} data
	 */
	timersIterator: function(data){ 
		var ret = new Array();
		for(var prop in data){
			if(prop != 'total'){
				ret.push(data[prop]);
			}
    	}
		return ret;
	},
	
	/**
	 * Converts the first character of a String to uppercase.
	 * @param {Object} value
	 */
	firstCharToUpper: function(value){
		var firstChar = value.substr(0, 1).toUpperCase();
		return firstChar + value.substr(1);
    },
	
	/**
	 * Appends the .png extension to a String
	 * @param {String} value
	 */
    appendPngExtension: function(value){
		return value + ".png";
    },
	
	/**
	 * Removes the sf prefix from a log type.
	 * @param {String} value
	 */
    formatLogType: function(value){
		if(value.indexOf('sf') == 0){
			value = value.substr(2);
		}
		return value;
    },

	/**
	 * Representations event handlers
	 */

	 //TODO rename it to toggleConfig or something more appropiate.
	sfWebDebugToggleMenu: function(event){
		var element = event.target.parentNode.parentNode.nextSibling;
		if (element.style.display != 'none'){
		  element.style.display = 'none';
		} else {
		  element.style.display = '';  
		}
		return false;
	},

	toggleAllLogs: function(event){
		var panel = FirebugContext.getPanel('firesymfony');
		var doc = panel.panelNode;
		var elements = doc.getElementsByTagName('tr');
		var display = (event.target.innerHTML.indexOf('all') > -1) ? '' : 'none';
		for(var i=1, maxLength = elements.length; i < maxLength; i++){
			var element = elements[i];
			element.style.display = display;
		}
    },

    togglePriority: function(event){
		var panel = FirebugContext.getPanel('firesymfony');
      	var doc = panel.panelNode;
      	var elements = doc.getElementsByTagName('tr');
      	for(var i=1, maxLength = elements.length; i < maxLength; i++){
			var element = elements[i];
        	if(element.className.indexOf(event.target.parentNode.id) > -1){
				element.style.display = '';
        	} else {
				element.style.display = 'none';
        	}
      	}
    },


    onTypeClick: function(event){
		var panel = FirebugContext.getPanel('firesymfony');
		var doc = panel.panelNode;
		var elements = doc.getElementsByClassName(event.target.innerHTML);
		for(var i=0, maxLength = elements.length; i < maxLength; i++){
			var element = elements[i];
			if(element.style.display != 'none'){
				element.style.display = 'none';
			} else {
				element.style.display = '';
			}
		}
    },
	
	// Firebug.Panel extension:
  
	name: "firesymfony",
	title: "symfony",
	symfonyData: {},

	initialize: function(context, doc) {
		Firebug.Panel.initialize.apply(this, arguments);
		Firebug.firesymfonyModel.addStyleSheet(this.document);
    
		if(typeof context.window.wrappedJSObject.FireSymfonyDebugData == 'undefined'){
			return;
    	} else {
      		this.symfonyData = context.window.wrappedJSObject.FireSymfonyDebugData;
    	}
	},
  
	getMainTabTag: function(id){
		var root = this.mainTag.replace({}, this.panelNode, null);
		return this.mainTabTag.replace({'id': id}, root, null);
	},
  
	displayCurrentView: function(){
		this.panelNode.innerHTML = "";
		this['render' + Firebug.firesymfonyModel.firesymfonyView + 'View']();
	},
  
	renderAboutView: function(){
		var where = this.panelNode;
		this.aboutTag.replace(this.symfonyData, where, null);
	},
  
	
	renderConfigView: function(){
		var where = this.getMainTabTag('sfWebDebugConfig');
		this.configurationDetailsTag.replace(this.symfonyData, where, null);
		this.configurationAndRequestTag.append(this.symfonyData, where, null);
	},
  
	renderLogsView: function(){
		var where = this.getMainTabTag('sfWebDebugLog');
    	this.logsHeadTag.replace(this.symfonyData, where, null);
    	this.logsTag.append(this.symfonyData, where, null);
	},
	
	renderCacheView: function(){
		var where = this.getMainTabTag('sfWebDebugCacheDetails');
		this.cacheHeadTag.replace(this.symfonyData, where, null);
		this.cacheTag.append(this.symfonyData, where, null);
	},
  
	renderDatabaseView: function(){
		var where = this.getMainTabTag('sfWebDebugDatabaseDetails');
    	this.databaseHeadTag.replace(this.symfonyData, where, null);
		this.databaseTag.append(this.symfonyData, where, null);
	},
  
	renderMemoryView: function(){
		var where = this.getMainTabTag('sfWebDebugMemoryDetails');
    	this.memoryTag.replace(this.symfonyData, where, null);
	},
  
	renderTimersView: function(){
	  	var where = this.getMainTabTag('sfWebDebugTimeDetails');
	    this.timersHeadTag.replace(this.symfonyData, where, null);
	    this.timersDetailsTag.append(this.symfonyData, where, null);
	}
  
});


Firebug.firesymfonyModel = extend(Firebug.Module,
{
  firesymfony_div: {},
  
  availableViews: ['About', 'Config', 'Logs', 'Cache', 'Database', 'Memory', 'Timers'],
  
  firesymfonyView: "About",
  
  loadedContext: function(context)
  {
  },
  
  addStyleSheet: function(doc)
  {
      // Make sure the stylesheet isn't appended twice.
      if ($("fsStyles", doc)) return;
      var styleSheet = createStyleSheet(doc, "chrome://firesymfony/skin/firesymfony.css");
      styleSheet.setAttribute("id", "fsStyles");
      addStyleSheet(doc, styleSheet);
  },
  
	reattachContext: function(browser, context)
	{
		var panel = context.getPanel('firesymfony');
		this.addStyleSheet(panel.document);
	},
  
  showPanel: function(browser, panel) {
    var isfiresymfonyPanel = panel && panel.name == "firesymfony";
    var firesymfonyButtons = browser.chrome.$("fbfiresymfonyButtons");
    collapse(firesymfonyButtons, !isfiresymfonyPanel);
    if (!isfiresymfonyPanel) return;
	this.changeCurrentView(this.firesymfonyView);
  },
  
  	/**
  	 * Called by showPanel or by the interface buttons to switch the panel view.
  	 * @param {String} view
  	 */
	changeCurrentView: function( view ) {
		this.firesymfonyView = view;
		FirebugContext.getPanel("firesymfony").displayCurrentView();
		this.toggleButtonStatus(view);
	},
	
	/**
	 * Toggles the buttons checked/unchecked status.
	 * @param {String} activeView - Indicates with button should be checked.
	 */
	toggleButtonStatus: function(activeView) {
		for(var i = 0, maxLength = this.availableViews.length; i < maxLength; i++){
			if(activeView == this.availableViews[i]){
				FirebugChrome.$("firesymfony" + this.availableViews[i] + "Button").checked = true;
			} else{
				FirebugChrome.$("firesymfony" + this.availableViews[i] + "Button").checked = false;
			}
		}
	},
  
  shutdown: function() {
    if(Firebug.getPref('defaultPanelName')=='firesymfony') 
    {
        /* Optional */
        Firebug.setPref('defaultPanelName','console');
	}
   }

});

Firebug.registerPanel(firesymfonyPanel);
Firebug.registerModule(Firebug.firesymfonyModel);

}});